#include <pfring.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include <sys/prctl.h>
#include <signal.h>

#include "common.h"
#include "change.h"

#define MAX_PACKET_SIZE 1500
int recv_num_i = 0;
int request_seq = 0;
char *dest_addr_str = "114.114.114.114";
char *device_name = "ens33";
int delay_second = 1;

void print_packet(const struct pfring_pkthdr *h, const u_char *p, u_int8_t dump_match)
{
    u_char *p_tmp = p;
    struct PING_PACKET ping_packet;

    if (*(p_tmp + 34) == 0 && *(p_tmp + 35) == 0)
    {
        memcpy(&(ping_packet.frame_header), p, 14);
        memcpy(&(ping_packet.ip_header), p + 14, 20);

        if (ping_packet.ip_header.sour_ip.s_addr == inet_addr(dest_addr_str))
        {
            recv_num_i++;
            printf("%d %s ms\n", request_seq + 1, inet_ntoa(ping_packet.ip_header.sour_ip));
            exit(0);
        }
    }

    if (*(p_tmp + 34) != 11)
        return;
    if (*(p_tmp + 35) != 0)
        return;

    memcpy(&(ping_packet.frame_header), p, 14);
    memcpy(&(ping_packet.ip_header), p + 14, 20);
    memcpy(&(ping_packet.icmp_echo), p + 34, 24);

    struct FRAME_HEADER *frame_header = &(ping_packet.frame_header);
    struct IP_HEADER *ip_header = &(ping_packet.ip_header);
    struct ICMP_ECHO *icmp_echo = &(ping_packet.icmp_echo);

    struct timeval tv_now; // 发送时间戳
    gettimeofday(&tv_now, NULL);
    float time_interval = calculate_time_interval(&(icmp_echo->tv), &tv_now);

    struct IP_HEADER old_ip_header;
    struct ICMP_ECHO old_icmp_echo;
    memcpy(&old_ip_header, p + 34 + 8, 20);
    memcpy(&old_icmp_echo, p + 34 + 8 + 20, sizeof(old_icmp_echo));
    request_seq = htons(old_icmp_echo.seq);
    recv_num_i++;
    printf("%d %s ms\n", request_seq, inet_ntoa(ip_header->sour_ip));
}

int send_packet(pfring *ring)
{

    // 构造帧头部
    struct PING_PACKET ping_packet;

    struct FRAME_HEADER *frame_header = &(ping_packet.frame_header);
    struct IP_HEADER *ip_header = &(ping_packet.ip_header);
    struct ICMP_ECHO *icmp_echo = &(ping_packet.icmp_echo);

    int len_frame_header = 0, len_ip_header = 0, len_icmp_echo = 0;

    len_frame_header = sizeof(*frame_header);
    len_ip_header = sizeof(*ip_header);
    len_icmp_echo = sizeof(*icmp_echo);

    //获取源目的地址
    pfring_get_bound_device_address(ring, frame_header->smac);
    char dmac_char[18] = "f8:8c:21:26:cc:91";
    mac_char_to_u_char(dmac_char, &(frame_header->dmac));

    frame_header->type = 0x0008;

    // 构造IP头部
    ip_header->sour_ip.s_addr = inet_addr("192.168.66.200");
    ip_header->dest_ip.s_addr = inet_addr(dest_addr_str);
    ip_header->vension_and_header = 0x45;
    ip_header->type_of_service = 0x00;
    // ip_header->lenght_of_packet=htons(len_ip_header+len_icmp_echo);
    ip_header->lenght_of_packet = 0x2e00;
    ip_header->id = 0xdc07;
    ip_header->flags_and_slice_info = 0x0000;
    ip_header->ttl = 0x40;
    ip_header->type_of_protocol = 0x01;
    // ip_header->checksum = htons(calculate_checksum((u_int16_t *)ip_header, len_ip_header));

    // // 构造ICMP 头部
    icmp_echo->type = 0x8;
    icmp_echo->code = 0x0;
    icmp_echo->seq = 0x0100;
    icmp_echo->ident = 0x0100;
    icmp_echo->checksum = 0x00;
    gettimeofday(&(icmp_echo->tv), NULL);
    // icmp_echo->checksum = htons(calculate_checksum((u_int16_t *)icmp_echo, len_icmp_echo + 2));

    int lenght_of_packet = len_frame_header + len_ip_header + len_icmp_echo;
    u_char buf[60];
    u_char buffer[MAX_PACKET_SIZE];

    if (ring == NULL)
        return -1;

    if (pfring_enable_ring(ring) != 0)
    {
        printf("Unable to enable ring :-(\n");
        pfring_close(ring);
        return (-1);
    }
    for (int i = 1; i <= 30; i++)
    {
        ip_header->ttl = i;
        icmp_echo->seq = htons(i % 65535);
        icmp_echo->checksum = htons(0);
        ip_header->checksum = htons(0);
        ip_header->checksum = htons(calculate_checksum((u_int16_t *)ip_header, len_ip_header));
        icmp_echo->checksum = htons(calculate_checksum((u_int16_t *)icmp_echo, len_icmp_echo));

        memset(buf, 0, 60);
        memcpy(buf, frame_header, len_frame_header);
        memcpy(buf + len_frame_header, ip_header, len_ip_header);
        memcpy(buf + len_frame_header + len_ip_header, icmp_echo, len_icmp_echo);

        pfring_send(ring, (char *)buf, 60, 1);
        sleep(1);
    }
}

int recived_packet(pfring *ring)
{

    u_int32_t flags = 265;
    // u_int32_t flags = 0;

    struct pfring_pkthdr hdr;
    u_char *buffer = NULL;
    int rc = 0;

    memset(&hdr, 0, sizeof(hdr));
    ring->break_recv_loop = ring->break_recv_loop_ext = 0;

    // if ((!ring) || ring->is_shutting_down || (!ring->recv) || ring->mode == send_only_mode)
    //     return -1;

    while (!ring->break_recv_loop_ext)
    {
        rc = ring->recv(ring, &buffer, 0, &hdr, 1);
        print_packet(&hdr, buffer, NULL);
    }
}
int main(int argc, char *argv[])
{

    // for (int i = 0; i < argc; i++)
    //     printf("%s\n", argv[i]);

    char c;
    while ((c = getopt(argc, argv, "i:t:w:")) != -1)
    {
        switch (c)
        {
        case 'i':
            device_name = strdup(optarg);
            break;
        case 't':
            dest_addr_str = strdup(optarg);
            break;

        case 'w':
            delay_second = (int)(*optarg - '0');
            printf("%d\n", delay_second);
            break;

        default:
            break;
        }
    }
    u_int32_t flags = 265;
    // u_int32_t flags = 0;
    pfring *ring = pfring_open(device_name, DEFAULT_SNAPLEN, flags);

    if (ring == NULL)
        return -1;

    printf("opened %s\n", device_name);

    pid_t fpid = fork();
    if (fpid == 0)
    {
        prctl(PR_SET_PDEATHSIG, SIGKILL);
        send_packet(ring);
    }
    else
    {
        recived_packet(ring);
    }
}